package com.wicket.okrrbff.common.util;

import org.apache.skywalking.apm.toolkit.trace.Tag;
import org.apache.skywalking.apm.toolkit.trace.Tags;
import org.apache.skywalking.apm.toolkit.trace.Trace;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author ：CHS
 * @since 2022/2/28 14:29
 *
 *
 * @version 1.0
 */
@Component
public class RedisUtil {

    @Autowired
    private RedisTemplate redisTemplate;

    public boolean isLockExist(String key) {
        return redisTemplate.hasKey(key);
    }

    public void add(String key, Object... values) {
        SetOperations<String, Object> setOperations = redisTemplate.opsForSet();
        setOperations.add(key, values);
    }

    public void set(String key, Object value) {
        //更改在redis里面查看key编码问题
        RedisSerializer redisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(redisSerializer);
        ValueOperations<String, Object> vo = redisTemplate.opsForValue();
        vo.set(key, value);
    }

    public void set(String key, Object value, long timeout, TimeUnit timeUnit) {
        //更改在redis里面查看key编码问题
        RedisSerializer redisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(redisSerializer);
        ValueOperations<String, Object> vo = redisTemplate.opsForValue();
        vo.set(key, value, timeout, timeUnit);
    }

    public void setDouble(String key, Double value) {
        //更改在redis里面查看key编码问题
        ValueOperations<String, Double> vo = redisTemplate.opsForValue();
        vo.set(key, value);
    }

    public Object get(String key) {
        ValueOperations<String, Object> vo = redisTemplate.opsForValue();
        return vo.get(key);
    }

    public boolean isExisit(String key) {
        return redisTemplate.hasKey(key);
    }

    public Boolean delete(String key) {
        return redisTemplate.delete(key);
    }



    public void expire(String key, long timeout) {
        redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 分布式锁
     * @param lockKey 锁标识
     * @param requestId 请求标识
     * @param expireTime 超时时间
     * @return
     */
    @Trace(operationName = "分布式锁加锁")
    @Tags({@Tag(key = "参数",value = "arg[0]"),
            @Tag(key = "返回值",value = "returnedObj")})
    public boolean getLock(String lockKey,String requestId,long expireTime){
        return redisTemplate.opsForValue().setIfAbsent(lockKey, requestId, expireTime, TimeUnit.SECONDS);
    }

    @Trace(operationName = "Redis原子加值")
    @Tags({@Tag(key = "参数",value = "arg[0]"),
            @Tag(key = "返回值",value = "returnedObj")})
    public void increase(String key,Double value){
        ValueOperations<String, Double> operations = redisTemplate.opsForValue();
        operations.increment(key,value);
    }

    public void setWithTimeOut(String key, Object value,Long timeOut) {
        //更改在redis里面查看key编码问题
        RedisSerializer redisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(redisSerializer);
        ValueOperations<String, Object> vo = redisTemplate.opsForValue();
        vo.set(key, value,timeOut,TimeUnit.SECONDS);
    }

    /**
     * 释放分布式锁
     * @param lockKey 锁标识
     * @param requestId 请求标识
     * @return
     */
    @Trace(operationName = "分布式锁解锁")
    @Tags({@Tag(key = "参数",value = "arg[0]"),
            @Tag(key = "返回值",value = "returnedObj")})
    public boolean releaseLock(String lockKey,String requestId){
        boolean result = false;
        try{
            Long RELEASE_SUCCESS = 1L;
            List<String> keys = new ArrayList<>();
            keys.add(lockKey);
            String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
            DefaultRedisScript<Long> defaultRedisScript = new DefaultRedisScript(script, Long.class);
            Long ret = (Long) redisTemplate.execute(defaultRedisScript, keys, requestId);
            if(RELEASE_SUCCESS.equals(ret)){
                result = true;
            }else{
                result = false;
            }
        }catch (Exception e){

        }

        return result;
    }

}
